package jaux.tank.generator.util;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

import org.apache.commons.lang3.StringUtils;

import jaux.tank.generator.domain.TankApplication;
import jaux.tank.generator.domain.TankEntity;
import jaux.tank.generator.domain.TankEnum;

public class AppUtil {
	
	private static final String ENTITY_MAPPER_SUFFIX = "Mapper";
	private static final String SERVICE_IMPL_SUFFIX = "Impl";
	private static final String DAO_SUFFIX = "Repository";
	private static final String QUERY_DTO_SUFFIX = "Query";
	private static final String SERVICE_SUFFIX = "Service";
	private static final String CONTROLLER_SUFFIX = "Controller";
	private static final String JAVA_FILE_EXT=".java";

	
	private AppUtil() {
	}
	
	
	public static String[] entityFiles(List<TankEntity> entities, TankApplication app) {
		if(entities == null|| entities.isEmpty()) {
			return new String[0];
		}
		return entities.stream()
				.filter(entity->entity!=null&& StringUtils.isNotBlank(entity.getName()))
				.map(entity->entityClassName(entity.getName(), app)+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	
	public static String entityClassName(String entityName, TankApplication app) {
		String entitySuffix = StringUtil.pascalCase(StringUtils.defaultIfBlank(app.getEntitySuffix(), ""));
		return StringUtil.pascalCase(entityName)+entitySuffix;
	}
	
	public static String entityTableName(TankEntity entity, TankApplication app) {
		if(entity == null|| StringUtils.isBlank(entity.getName())) {
			return "";
		}
		String tablePrefix = StringUtil.snakeCase(StringUtils.defaultIfBlank(app.getTankPrefix(), app.getName()));
		return (StringUtils.isBlank(tablePrefix)?"":(tablePrefix+"_"))
				+StringUtil.snakeCase(entity.getTableName());
	}
	
	
	public static String dtoClassName(String entityName, TankApplication app) {
		String dtoSuffix = StringUtil.pascalCase(StringUtils.defaultIfBlank(app.getDtoSuffix(), "DTO"));
		return StringUtil.pascalCase(entityName)+dtoSuffix;
	}
	
	public static String[] dtoFiles(List<TankEntity> entities, TankApplication app) {
		if(entities == null || entities.isEmpty()) {
			return new String[0];
		}
		return entities.stream()
				.filter(e->e!=null && StringUtils.isNotBlank(e.getName()) && TankEntity.DTO.MAPSTRUCT.equals(e.getDto()))
				.map(e->dtoClassName(e.getName(), app)+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	
	public static String mapperClassName(String entityName ) {
		return StringUtil.pascalCase(entityName)+ENTITY_MAPPER_SUFFIX;
	}
	
	public static String[] mapperFiles(List<TankEntity> entities, TankApplication app) {
		if(entities == null || entities.isEmpty()) {
			return new String[0];
		}
		return entities.stream()
				.filter(e->e!=null && StringUtils.isNotBlank(e.getName())&& TankEntity.DTO.MAPSTRUCT.equals(e.getDto()))
				.map(e->mapperClassName(e.getName())+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	public static String entityNameByMapper(String mapperName) {
		if(mapperName == null|| mapperName.isBlank()) {
			return null;
		}
		return mapperName.substring(0, mapperName.length()-ENTITY_MAPPER_SUFFIX.length());
	}
	
	public static String entityNameByDto(String dto, TankApplication app) {
		if(dto == null || app==null) {
			return null;
		}
		String dtoSuffix = StringUtil.pascalCase(StringUtils.defaultIfBlank(app.getDtoSuffix(), "DTO"));
		return dto.substring(0, dto.length()-dtoSuffix.length());
	}
	
	public static String[] enumFiles(List<TankEnum> enums, TankApplication app) {
		if(enums == null|| enums.isEmpty()) {
			return new String[0];
		}
		return enums.stream()
				.filter(e->e!=null&& StringUtils.isNotBlank(e.getName()))
				.map(e->StringUtil.pascalCase(e.getName())+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	
	public static String[] queryDtoFiles(List<TankEntity> entities, TankApplication app) {
		if(entities == null|| entities.isEmpty()) {
			return new String[0];
		}
		return entities.stream()
				.filter(e->e!=null&& StringUtils.isNotBlank(e.getName()) && e.isFiltered())
				.map(e->StringUtil.pascalCase(e.getName())+QUERY_DTO_SUFFIX+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	
	public static String[] serviceFiles(List<TankEntity> entities, TankApplication app) {
		if(entities == null|| entities.isEmpty()) {
			return new String[0];
		}
		Predicate<? super TankEntity> entityFilter = e->e!=null
				&& StringUtils.isNotBlank(e.getName())
				&& e.getServiceType()!=null
				&& !TankEntity.ServiceType.NO.equals(e.getServiceType())
				&& !TankEntity.ServiceType.RESOURCE.equals(e.getServiceType());
		return entities.stream()
				.filter(entityFilter)
				.map(e->StringUtil.pascalCase(e.getName())+SERVICE_SUFFIX+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	public static String[] serviceImplFiles(List<TankEntity> entities, TankApplication app) {
		String[] serviceFiles= serviceFiles(entities, app);
		if(serviceFiles == null|| serviceFiles.length==0) {
			return new String[0];
		}
		return Arrays.stream(serviceFiles)
				.map(e->e.substring(0, e.length()-JAVA_FILE_EXT.length())+SERVICE_IMPL_SUFFIX+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	
	public static String[] controllerFiles(List<TankEntity> entities, TankApplication app) {
		if(entities == null|| entities.isEmpty()) {
			return new String[0];
		}
		Predicate<? super TankEntity> entityFilter = e->e!=null
				&& StringUtils.isNotBlank(e.getName())
				&& e.getServiceType()!=null
				&& !TankEntity.ServiceType.NO.equals(e.getServiceType())
				&& !TankEntity.ServiceType.RESOURCE.equals(e.getServiceType());
		return entities.stream()
				.filter(entityFilter)
				.map(e->StringUtil.pascalCase(e.getName())+CONTROLLER_SUFFIX+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	
	public static String[] daoFiles(List<TankEntity> entities, TankApplication app) {
		if(entities == null|| entities.isEmpty()) {
			return new String[0];
		}
		return entities.stream()
				.filter(e->e!=null&& StringUtils.isNotBlank(e.getName()))
				.map(e->StringUtil.pascalCase(e.getName())+DAO_SUFFIX+JAVA_FILE_EXT)
				.toArray(String[]::new);
	}
	
	public static TankEntity getEntity(List<TankEntity> entities, String name) {
		if(entities == null|| entities.isEmpty()) {
			return null;
		}
		return entities.stream()
				.filter(e->e!=null&& StringUtils.isNotBlank(e.getName())&& name.equals(e.getName()))
				.findFirst()
				.orElse(null);
	}
}
